package org.luckyjourney.controller.wx;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson2.JSONObject;
import com.wechat.pay.java.service.payments.jsapi.model.PrepayWithRequestPaymentResponse;
import com.wechat.pay.java.service.payments.model.Transaction;
import com.wechat.pay.java.service.refund.model.Refund;
import com.wechat.pay.java.service.refund.model.Status;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.luckyjourney.entity.booking.Orders;
import org.luckyjourney.entity.booking.dto.OrdersPaymentDTO;
import org.luckyjourney.entity.booking.vo.RefundsVO;
import org.luckyjourney.exception.BaseException;
import org.luckyjourney.mapper.booking.OrdersMapper;
import org.luckyjourney.service.booking.OrdersService;
import org.luckyjourney.service.booking.WechatPayService;
import org.luckyjourney.util.AesUtil;
import org.luckyjourney.util.Result;
import org.luckyjourney.util.UtilClass;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.io.IOException;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.security.GeneralSecurityException;

@RestController
@Api(tags = "微信支付接口")
@RequestMapping("wechatPay")
@Slf4j
public class WechatPayController {
    @Resource
    private WechatPayService wechatPayService;
    @Resource
    private WechatPayConfig wechatPayConfig;
    @Autowired
    OrdersService ordersService;
    @Autowired
    OrdersMapper ordersMapper;

    //前端首先调用此接口获取到用户唯一标识openId，用于后续调起支付的传参
    @ApiOperation("获取openid和session_key")
    @GetMapping("getOpenIdAndSessionKey")
    public com.alibaba.fastjson.JSONObject getOpenIdAndSessionKey(String code) {
        return UtilClass.getOpenIdAndSessionKey(code, wechatPayConfig.getAppId(), wechatPayConfig.getAppSecret());
    }


    @ApiOperation("调起支付")
    @PostMapping("pay")
    public synchronized Result prepayWithRequestPayment(@RequestBody OrdersPaymentDTO ordersPaymentDTO) {
        String ordersNumber = ordersPaymentDTO.getOrdersNumber();
        Orders orders = ordersMapper.selectOrdersNumber(ordersNumber);
        if (ObjectUtil.isEmpty(orders)) {
            throw new BaseException("没有该订单信息");
        }
        BigDecimal price = orders.getPrice();
        Integer total = price.multiply(new BigDecimal(100)).setScale(2, BigDecimal.ROUND_HALF_UP).intValue();
        //如果价格未0
        if (total == 0) {
            ordersService.paySuccess(ordersNumber);
            return Result.success("支付成功");
        }
        PrepayWithRequestPaymentResponse response = wechatPayService.prepayWithRequestPayment(ordersPaymentDTO);

        return Result.success(response);
    }


    @ApiOperation("微信退款")
    @PostMapping("refund")
    public synchronized Refund prepayWithRefundRequests(@RequestBody OrdersPaymentDTO ordersPaymentDTO) {
        return wechatPayService.prepayWithRefundRequests(ordersPaymentDTO);
    }

    @ApiOperation("退款详情")
    @PostMapping("details")
    public Result refunddetails(@RequestBody OrdersPaymentDTO ordersPaymentDTO) {
        RefundsVO refunds = wechatPayService.refunddetails(ordersPaymentDTO);
        return Result.success(refunds);
    }


    @ApiOperation("申请退款")
    @PostMapping("refunds")
    public Result RequesRefund(@RequestBody OrdersPaymentDTO ordersPaymentDTO) {
        Boolean aBoolean = wechatPayService.RequesRefund(ordersPaymentDTO);
        if (aBoolean.equals(true)) {
            return Result.success("退款申请成功，等待咨询师确认");
        }
        return Result.error("退款申请失败");
    }

    @ApiOperation("取消退款申请")
    @PostMapping("cancelRefund")
    public Result cancelRefund(@RequestBody OrdersPaymentDTO ordersPaymentDTO) {
        Boolean aBoolean = wechatPayService.cancelRefund(ordersPaymentDTO);
        if (aBoolean.equals(true)) {
            return Result.success("取消成功");
        }
        return Result.error("取消失败");
    }

    @ApiOperation("微信支付订单号查询订单")
    @GetMapping("queryOrderById/{ordersNumber}")
    public synchronized Transaction queryOrderById(@PathVariable String ordersNumber) {
        Transaction transaction = wechatPayService.queryOrderById(ordersNumber);
        Transaction.TradeStateEnum tradeState = transaction.getTradeState();
        String tradeStates = tradeState.toString();
        if (tradeStates.equals("SUCCESS")) {
            //业务处理，修改订单状态、来单提醒
            ordersService.paySuccess(transaction.getOutTradeNo());
        }
        return transaction;
    }

    @ApiOperation("查询单笔退款金额")
    @GetMapping("refundSuccess/{refundOrdersNumber}")
    public synchronized Refund refundSuccess(@PathVariable String refundOrdersNumber) {
        //微信封装好的方法
        Refund refund = wechatPayService.refundSuccess(refundOrdersNumber);
        Status status = refund.getStatus();
        String refundStates = status.toString();
        if (refundStates.equals("SUCCESS")) {
            //业务处理，修改订单状态、来单提醒
            ordersService.refundSuccess(refund.getOutRefundNo());
        }
        return refund;
    }


    //支付成功后微信会自动调用此接口
    @ApiOperation("支付成功的回调")
    @PostMapping("notify-pay")
    public Object callBackWeiXinPay(@RequestBody JSONObject jsonObject) {
        try {
            String key = wechatPayConfig.getApiV3Key();
            String json = jsonObject.toString();
            //解密 jsonObject 对象
            String associated_data = (String) JSONUtil.getByPath(JSONUtil.parse(json), "resource.associated_data");
            String ciphertext = (String) JSONUtil.getByPath(JSONUtil.parse(json), "resource.ciphertext");
            String nonce = (String) JSONUtil.getByPath(JSONUtil.parse(json), "resource.nonce");
            //数据解密
            String decryptData = new AesUtil(key.getBytes(StandardCharsets.UTF_8)).decryptToString
                    (associated_data.getBytes(StandardCharsets.UTF_8),
                            nonce.getBytes(StandardCharsets.UTF_8),
                            ciphertext);
            JSONObject decryptDataObj = JSONObject.parseObject(decryptData, JSONObject.class);
            if ("支付成功".equals(decryptDataObj.get("trade_state_desc"))) {
                //支付成功后的业务操作
                String outTradeNo = decryptDataObj.getString("out_trade_no");//商户平台订单号
                String transactionId = decryptDataObj.getString("transaction_id");//微信支付交易号
                log.info("商户平台订单号：{}", outTradeNo);
                log.info("微信支付交易号：{}", transactionId);
                //业务处理，修改订单状态、来单提醒
                ordersService.paySuccess(outTradeNo);
            }
        } catch (GeneralSecurityException | IOException e) {
            throw new RuntimeException(e);
        }
        return new Object();
    }

    //支付成功后微信会自动调用此接口
    @ApiOperation("退款成功的回调")
    @PostMapping("notify-refund")
    public Object refundWeiXinPay(@RequestBody JSONObject jsonObject) {
        try {
            String key = wechatPayConfig.getApiV3Key();
            String json = jsonObject.toString();
            //解密 jsonObject 对象
            String associated_data = (String) JSONUtil.getByPath(JSONUtil.parse(json), "resource.associated_data");
            String ciphertext = (String) JSONUtil.getByPath(JSONUtil.parse(json), "resource.ciphertext");
            String nonce = (String) JSONUtil.getByPath(JSONUtil.parse(json), "resource.nonce");
            //数据解密
            String decryptData = new AesUtil(key.getBytes(StandardCharsets.UTF_8)).decryptToString
                    (associated_data.getBytes(StandardCharsets.UTF_8),
                            nonce.getBytes(StandardCharsets.UTF_8),
                            ciphertext);
            JSONObject decryptDataObj = JSONObject.parseObject(decryptData, JSONObject.class);
            if ("退款成功".equals(decryptDataObj.get("summary"))) {
                //退款成功后的业务操作
                String outRefundNo = decryptDataObj.getString("out_refund_no");//商户平台订单号
                String transactionId = decryptDataObj.getString("transaction_id");//微信支付交易号
                log.info("商户平台退款订单号：{}", outRefundNo);
                log.info("微信支付交易号：{}", transactionId);
                //业务处理，修改订单状态、来单提醒
                ordersService.refundSuccess(outRefundNo);
            }
        } catch (GeneralSecurityException | IOException e) {
            throw new RuntimeException(e);
        }
        return new Object();
    }
}
